#include "StdAfx.h"
#include "Server.hpp"
#include "Listener.hpp"
#include "LinkedList.hpp"

HpsFramework::Network::Server::Server( void ) 
	: _running(false), _listener(NULL), _factory(NULL), _writerThread(NULL), _protocol(NULL)
{
	this->_writerThread.setServer(this);
	this->_acceptor.setServer(this);
}

HpsFramework::Network::Server::~Server( void )
{
}

bool HpsFramework::Network::Server::isRunning()
{
	return this->_running;
}

HpsFramework::Network::ServerIocpController* HpsFramework::Network::Server::getIoController()
{
	return &this->_iocp;
}

bool HpsFramework::Network::Server::startServer( Network::Address& addr, bool dist /*= true*/, size tpp /*= 1 */ )
{

	if(this->isRunning())
	{
		return false;
	}

	if(!this->_listener)
	{
		this->_listener = &this->_acceptor;
	}

	this->onServerStarting();

	if(!this->_iocp.create())
	{
		this->onServerError("IOCP engine has failed starting", GetLastError());
		this->_iocp.terminate();
		return false;
	}

	if(this->_listener->startListening(addr))
	{
		bool ret = this->startWorkers ( tpp, dist );
		if(ret)
		{
			ret = this->_writerThread.start();
			if(ret)
			{
				this->_address = addr;
				this->_running = true;
				this->onServerStart();
			}
		}
		else
		{
			this->onServerError("Server has failed starting worker threads", GetLastError());
		}
		if(!ret)
		{
			this->_listener->stopListening();
			this->_iocp.terminate();
			this->stopWorkers();
		}
		return ret;
	}

	this->onServerError("Server has failed starting...", WSAGetLastError());
	return false;
}

bool HpsFramework::Network::Server::stopServer()
{

	if(this->_running)
	{

		this->onServerClosing();

		this->_listener->stopListening();

		this->_iocp.terminate();

		this->stopWorkers();

		this->_running = false;

		this->onServerClose();

		return true;

	}

	return false;

}

void HpsFramework::Network::Server::stopWorkers()
{
	if(!this->_workerList.isEmpty())
	{
		this->_workerPool.stop();
	}

	while(!this->_workerList.isEmpty())
	{
		ServerWorker* worker = this->_workerList.getFirst()->getContent();
		this->_workerList.removeFirst();
		delete worker;
	}
}

bool HpsFramework::Network::Server::startWorkers( size count /*= 2*/, bool distributed /*= true */ )
{
	SYSTEM_INFO si;
	GetSystemInfo(&si);

	this->stopWorkers();

	si.dwNumberOfProcessors *= count;

	for(size i = 0; i < si.dwNumberOfProcessors; i++)
	{
		ServerWorker* worker = new ServerWorker(this);
		this->_workerPool.associate(worker);
		this->_workerList.addLast(worker);
	}

	if(!this->_workerPool.pool(distributed))
	{
		this->stopWorkers();
		return false;
	}

	return true;
}

HpsFramework::Network::Listener* HpsFramework::Network::Server::getListener()
{
	return this->_listener;
}

void HpsFramework::Network::Server::setFilter( HpsFramework::Network::Listener* listener )
{
	if(listener)
		listener->setServer(this);
	this->_listener = listener;
}

void HpsFramework::Network::Server::setClientFactory( HpsFramework::Network::ClientFactory* factory )
{
	if(factory)
		factory->setServer(this);
	this->_factory = factory;
}

void HpsFramework::Network::Server::updateServer()
{

	ListContainer<Client*> temp;

	StartListIteration(Client*, this->getClientManager())
	{

		if(CurrentNode)
		{

			Client* context = CurrentNode->getContent();
			if(context)
			{

				if(context->isValid() && !context->isRemoveSet())
				{
					// Check for idle states
				}
				else if(context->isDisconnectionSet())
				{
					if(context->getWriter()->getBuffer()->getUsedSpace() <= 0)
					{
						context->setRemoval();
						ContinueListIteration();
					}
				}

				if(context->isRemoveSet())
				{
					context->onDisconnect();
					temp.addLast(context);
				}

			}

		}

		CurrentNode = GetNextNode();

	}
	FinishListIteration();

	if(!temp.isEmpty())
	{
		StartListIteration(Client*, &temp)
		{
			Client* context = CurrentNode->getContent();
			this->getClientManager()->removeClient(context);
			this->getClientFactory()->destroyClient(context);
			CurrentNode = GetNextNode();
		}
		FinishListIteration();
	}

}

HpsFramework::Network::Address* HpsFramework::Network::Server::getBindAddress()
{
	return &this->_address;
}

HpsFramework::Network::ClientManager* HpsFramework::Network::Server::getClientManager()
{
	return &this->_manager;
}

HpsFramework::Network::ClientFactory* HpsFramework::Network::Server::getClientFactory()
{
	return this->_factory;
}

void HpsFramework::Network::Server::setProtocolHandler( Protocol::ProtocolHandler* protocol )
{
	this->_protocol = protocol;
}

HpsFramework::Network::Protocol::ProtocolHandler* HpsFramework::Network::Server::getProtocolHandler()
{
	return this->_protocol;
}
